#define BLINKER_WIFI
#define BLINKER_MIOT_OUTLET
#include <ESP32Servo.h>
#include <WiFi.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Blinker.h>

// WiFi 相关配置
const char* ssid     = "a";
const char* password = "030422zcl";

WiFiServer server(80);

Servo myservo;  // 创建舵机对象以控制舵机

int angle=170;
int servoPin = 9; // 舵机控制引脚

#define RST_PIN     12          // 可配置，参见典型引脚布局
#define SS_PIN      4           // 可配置，参见典型引脚布局

MFRC522 mfrc522(SS_PIN, RST_PIN);  // 创建 MFRC522 实例

// Blinker 相关配置
char auth[] = " ";
#define BUTTON_1 "ButtonKey"
BlinkerButton Button1(BUTTON_1);

bool oState = false;  // 设备状态

void button1_callback(const String & state) {
  BLINKER_LOG("get button state: ", state);
  if (state == BLINKER_CMD_BUTTON_TAP) {
    BLINKER_LOG("Button tap!");
    toggleServo();
  }
}

void miotPowerState(const String & state) {
  BLINKER_LOG("need set power state: ", state);

  if (state == BLINKER_CMD_ON) {
    toggleServo() ;
    BlinkerMIOT.powerState("on");
    BlinkerMIOT.print();
    oState = true;
  }
}

void miotQuery(int32_t queryCode) {
  BLINKER_LOG("MIOT Query codes: ", queryCode);

  switch (queryCode) {
    case BLINKER_CMD_QUERY_ALL_NUMBER :
      BLINKER_LOG("MIOT Query All");
      BlinkerMIOT.powerState(oState ? "on" : "off");
      BlinkerMIOT.print();
      break;
    case BLINKER_CMD_QUERY_POWERSTATE_NUMBER :
      BLINKER_LOG("MIOT Query Power State");
      BlinkerMIOT.powerState(oState ? "on" : "off");
      BlinkerMIOT.print();
      break;
    default :
      BlinkerMIOT.powerState(oState ? "on" : "off");
      BlinkerMIOT.print();
      break;
  }
}

void setup() {
  Serial.begin(9600);       // 初始化串口
  SPI.begin(2,10,3,4);      // 初始化 SPI 总线
  mfrc522.PCD_Init();       // 初始化 MFRC522

  pinMode(RST_PIN, OUTPUT); // 设置复位引脚为输出
  digitalWrite(RST_PIN, HIGH); // 初始化复位引脚为高电平（未复位）
  myservo.attach(servoPin); // 将舵机连接到引脚 9

  // 连接到 WiFi
  WiFi.begin(ssid, password);
  Serial.println("connecting WiFi...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
  // 启动服务器
  server.begin();

  // 初始化 Blinker
  Blinker.begin(auth, ssid, password);
  Button1.attach(button1_callback);

  // 设置小爱同学控制
  BlinkerMIOT.attachPowerState(miotPowerState);
  BlinkerMIOT.attachQuery(miotQuery);
}

void loop() {
  Blinker.run(); // 运行 Blinker

  // 检查是否有新的 NFC 标签
  if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
    Serial.println("checked NFC label");
    // 打印标签的 UID
    Serial.print("UID: ");
    String uidStr = "";
    for (byte i = 0; i < mfrc522.uid.size; i++) {
      Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
      Serial.print(mfrc522.uid.uidByte[i], HEX);
      uidStr += String(mfrc522.uid.uidByte[i], HEX);
    }
    Serial.println();

    // 将 UID 字符串转换为大写
    uidStr.toUpperCase();

    // 检查 UID 并根据结果执行相应操作
    if (checkUID(uidStr)) {
      // 授权标签的操作
      toggleServo(); // 切换舵机位置
    } else {
      // 未授权标签的操作
      Serial.println("ungrantlabel");
    }
    delay(1000); // 延迟以防止读取同一标签多次
  } else {
    // 如果未检测到新卡，可能需要复位RC522
    resetRC522();
  }

  // 检查是否有 WiFi 客户端连接
  WiFiClient client = server.available();
  if (client) {
    Serial.println("connecting...");
    String currentLine = "";
    bool isPost = false;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n') {
          if (currentLine.length() == 0) {
            if (isPost) {
              // 读取POST数据
              String postData = "";
              while (client.available()) {
                char c = client.read();
                postData += c;
              }
              // 解析POST数据
              if (postData.indexOf("angle=") >= 0) {
                int angleStart = postData.indexOf("angle=") + 6;
                int angleEnd = postData.indexOf("&", angleStart);
                if (angleEnd == -1) { // 如果找不到&，则到行末
                  angleEnd = postData.length();
                }
                String angleStr = postData.substring(angleStart, angleEnd);
                angle = angleStr.toInt();
                Serial.print(angleStr);
                if (angle >= 0 && angle <= 180) {
                  toggleServo(); 
                }
              }
            }
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html; charset=utf-8");
            client.println();
            client.print("<div style='font-size:40px;text-align:center;margin:20 auto;'>宿舍开门</div><br/><br/>");
            client.print("<a href=\"/10\">固定角度开门</a>");
            client.print("<form method=\"post\">");
            client.print("输入角度: <input type=\"text\" name=\"angle\" />");
            client.print("<input type=\"submit\" value=\"灵活角度开门\" />");
            client.print("</form>");
            client.println();
            break;
          } else {
            if (currentLine.startsWith("POST")) {
              isPost = true;
            }
            if (currentLine.startsWith("GET /10")) {
              toggleServo(); 
            }
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }
      }
    }
    client.stop();
    Serial.println("disconnected...");
  }
}

void resetRC522() {
  digitalWrite(RST_PIN, LOW); // 拉低复位引脚
  delay(50);                  // 延时50毫秒
  digitalWrite(RST_PIN, HIGH); // 拉高复位引脚
  delay(50);                  // 延时50毫秒
  mfrc522.PCD_Init();         // 重新初始化 MFRC522
}

// 检查读取的 UID 是否与授权 UID 匹配
bool checkUID(String uidStr) {
  // 定义授权的 UID（十六进制格式）
  String authorizedUIDStr = "23AFB227"; // 示例授权 UID

  // 将 UID 字符串转换为大写以进行不区分大小写的比较
  uidStr.toUpperCase();
  authorizedUIDStr.toUpperCase();

  // 检查读取的 UID 是否与授权 UID 匹配
  return uidStr.equals(authorizedUIDStr);
}

// 切换舵机位置的函数
void toggleServo() {
  myservo.write(angle); // 舵机角度 angle
  delay(3000);
  myservo.write(180); // 恢复到中间位置
}
